use lazy_static::lazy_static;
use port_selector::{self, select_free_port, Selector};
use std::process::Child;
use std::sync::{Arc, Mutex};
use std::{
    env,
    io::{self, BufRead},
    process::{Command, Stdio},
};
use tauri::{Manager, Window};
#[tauri::command]
pub fn get_free_port(min: u16, max: u16) -> Option<u16> {
    let selector = Selector {
        check_tcp: true,
        check_udp: true,
        port_range: (min, max),
        max_random_times: 100,
    };
    select_free_port(selector)
}

#[derive(Clone, serde::Serialize)]
struct Payload {
    message: String,
    current_dir: String,
}
struct ChildProcess {
    child: std::process::Child,
    command: String,
    id: u32,
}

lazy_static! {
    static ref CHILDREN: Arc<Mutex<Vec<ChildProcess>>> = Arc::new(Mutex::new(Vec::new()));
}

#[tauri::command]
pub async fn run_cmd(window: Window, command: String) -> u32 {
    let cmd_clone = command.clone();
    let command = Command::new("cmd")
        .args(&["/C", &command])
        .stdout(Stdio::piped())
        .spawn();
    let mut child = match command {
        Ok(child) => child,
        Err(_e) => create_default_child(),
    };
    let id = child.id();
    if let Some(stdout) = child.stdout.take() {
        let reader = io::BufReader::new(stdout);
        let child_process = ChildProcess {
            child,
            command: cmd_clone,
            id,
        };
        CHILDREN.lock().unwrap().push(child_process);
        for line in reader.lines() {
            match line {
                Ok(text) => {
                    if let Ok(current_dir) = env::current_dir() {
                        // 将 PathBuf 转换为 String
                        window
                            .emit_all(
                                "cmd_output",
                                Payload {
                                    message: text.into(),
                                    current_dir: current_dir.to_string_lossy().into_owned().into(),
                                },
                            )
                            .unwrap();
                    } else {
                        eprintln!("无法获取当前工作目录");
                    }
                }
                Err(e) => eprintln!("Error reading line: {}", e),
            }
        }
    }
    id
}

fn create_default_child() -> Child {
    let default_command = "echo";
    let default_args = vec!["Hello", "World"];

    Command::new(default_command)
        .args(default_args)
        .spawn()
        .expect("Failed to create default child process")
}

#[tauri::command]
pub async fn kill_all_child() {
    let mut children = CHILDREN.lock().unwrap();
    for child_process in children.iter_mut() {
        if let Err(err) = child_process.child.kill() {
            eprintln!(
                "Failed to kill child process {}: {}",
                child_process.command, err
            );
        }
    }
    children.clear();
}
#[tauri::command]
pub async fn kill_child(id: u32) {
    let mut children = CHILDREN.lock().unwrap();
    let index_to_remove = children
        .iter()
        .position(|child_process| child_process.id == id);

    if let Some(index) = index_to_remove {
        if let Err(err) = children[index].child.kill() {
            eprintln!(
                "Failed to kill child process {}: {}",
                children[index].command, err
            );
        } else {
            children.remove(index);
        }
    }
}
